home *** CD-ROM | disk | FTP | other *** search
/ Best Tools for JAVA / Best Tools for JAVA.iso / JAVA_ALL / IDE / DUMPCLAS.TAR / util / ClassFile.java < prev    next >
Encoding:
Java Source  |  1996-05-22  |  25.0 KB  |  788 lines

  1. /*
  2.  * ClassFile.java    Chuck McManis
  3.  *
  4.  * Copyright (c) 1996 Chuck McManis, All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies.
  10.  *
  11.  * CHUCK MCMANIS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
  12.  * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  13.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  14.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. CHUCK MCMANIS SHALL NOT BE
  15.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
  16.  * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  17.  */
  18.  
  19. package util;
  20.  
  21. import java.util.*;
  22. import java.io.*;
  23.  
  24. /**
  25.  * This class is used to manipulate Java class files in strange and
  26.  * mysterious ways.
  27.  *
  28.  * Usage it typically to feed it an array of bytes that are a class
  29.  * file, manipulate the class, then convert the class back into bytes,
  30.  * and feed the final result to <TT>defineClass()</TT>.
  31.  *
  32.  * @version     1.6, 19 Aug 1995
  33.  * @author    Chuck McManis
  34.  * @see        AttributeInfo
  35.  * @see        ConstantPoolInfo
  36.  * @see        MethodInfo
  37.  * @see        FieldInfo
  38.  */
  39.  
  40. public class ClassFile {
  41.     int                    magic;
  42.     short                majorVersion;
  43.     short               minorVersion;
  44.     ConstantPoolInfo    constantPool[];
  45.     short                accessFlags;
  46.     ConstantPoolInfo    thisClass;
  47.     ConstantPoolInfo    superClass;
  48.     ConstantPoolInfo    interfaces[];
  49.     FieldInfo            fields[];
  50.     MethodInfo            methods[];
  51.     AttributeInfo        attributes[];
  52.     boolean                isValidClass = false;
  53.  
  54.     public static final int ACC_PUBLIC         = 0x1;
  55.     public static final int ACC_PRIVATE     = 0x2;
  56.     public static final int ACC_PROTECTED     = 0x4;
  57.     public static final int ACC_STATIC         = 0x8;
  58.     public static final int ACC_FINAL         = 0x10;
  59.     public static final int ACC_SYNCHRONIZED     = 0x20;
  60.     public static final int ACC_THREADSAFE     = 0x40;
  61.     public static final int ACC_TRANSIENT     = 0x80;
  62.     public static final int ACC_NATIVE         = 0x100;
  63.     public static final int ACC_INTERFACE     = 0x200;
  64.     public static final int ACC_ABSTRACT     = 0x400;
  65.  
  66.     public boolean debug = false;
  67.     public boolean dumpConstants = false;
  68.     /**
  69.      * Read a class from InputStream <i>in</i>.
  70.      */
  71.     public boolean read(InputStream in)
  72.     throws IOException {
  73.         DataInputStream di = new DataInputStream(in);
  74.         int    count;
  75.  
  76.         magic = di.readInt();
  77.         if (magic != (int) 0xCAFEBABE) {
  78.             return (false);
  79.         }
  80.  
  81.         majorVersion = di.readShort();
  82.         minorVersion = di.readShort();
  83.         count = di.readShort();
  84.         constantPool = new ConstantPoolInfo[count];
  85.         if (debug)
  86.             System.out.println("read(): Read header...");
  87.         constantPool[0] = new ConstantPoolInfo();
  88.         for (int i = 1; i < constantPool.length; i++) {
  89.             constantPool[i] = new ConstantPoolInfo();
  90.             if (! constantPool[i].read(di)) {
  91.                 return (false);
  92.             }
  93.             // These two types take up "two" spots in the table
  94.             if ((constantPool[i].type == ConstantPoolInfo.LONG) ||
  95.                 (constantPool[i].type == ConstantPoolInfo.DOUBLE))
  96.                 i++;
  97.         }
  98.  
  99.         /*
  100.          * Update pointers in the constant table. This turns the
  101.           * table into a real datastructure.
  102.           *
  103.          * TODO: Have it verify that the right arguments are present
  104.           */
  105.         for (int i = 1; i < constantPool.length; i++) {
  106.             if (constantPool[i] == null)
  107.                 continue;
  108.             if (constantPool[i].index1 > 0)
  109.                 constantPool[i].arg1 = constantPool[constantPool[i].index1];
  110.             if (constantPool[i].index2 > 0)
  111.                 constantPool[i].arg2 = constantPool[constantPool[i].index2];
  112.         }
  113.  
  114.         if (dumpConstants) {
  115.             for (int i = 1; i < constantPool.length; i++) {
  116.                 System.out.println("C"+i+" - "+constantPool[i]);
  117.             }
  118.           }
  119.         accessFlags = di.readShort();
  120.  
  121.         thisClass = constantPool[di.readShort()];
  122.         superClass = constantPool[di.readShort()];
  123.         if (debug)
  124.             System.out.println("read(): Read class info...");
  125.  
  126.         /*
  127.           * Identify all of the interfaces implemented by this class
  128.           */
  129.         count = di.readShort();
  130.         if (count != 0) {
  131.             if (debug)
  132.                 System.out.println("Class implements "+count+" interfaces.");
  133.             interfaces = new ConstantPoolInfo[count];
  134.             for (int i = 0; i < count; i++) {
  135.                 int iindex = di.readShort();
  136.                 if ((iindex < 1) || (iindex > constantPool.length - 1))
  137.                     return (false);
  138.                 interfaces[i] = constantPool[iindex];
  139.                 if (debug)
  140.                     System.out.println("I"+i+": "+interfaces[i]);
  141.             }
  142.         }
  143.         if (debug)
  144.             System.out.println("read(): Read interface info...");
  145.  
  146.         /*
  147.          * Identify all fields in this class.
  148.          */
  149.         count = di.readShort();
  150.         if (debug)
  151.             System.out.println("This class has "+count+" fields.");
  152.         if (count != 0) {
  153.             fields = new FieldInfo[count];
  154.             for (int i = 0; i < count; i++) {
  155.                 fields[i] = new FieldInfo();
  156.                 if (! fields[i].read(di, constantPool)) {
  157.                    return (false);
  158.                 }
  159.                 if (debug)
  160.                     System.out.println("F"+i+": "+
  161.                         fields[i].toString(constantPool));
  162.             }
  163.         }
  164.         if (debug)
  165.             System.out.println("read(): Read field info...");
  166.  
  167.         /*
  168.            * Identify all the methods in this class.
  169.          */
  170.         count = di.readShort();
  171.         if (count != 0) {
  172.             methods = new MethodInfo[count];
  173.             for (int i = 0; i < count; i++) {
  174.                 methods[i] = new MethodInfo();
  175.                 if (! methods[i].read(di, constantPool)) {
  176.                     return (false);
  177.                 }
  178.                 if (debug)
  179.                     System.out.println("M"+i+": "+methods[i].toString());
  180.             }
  181.         }
  182.         if (debug)
  183.             System.out.println("read(): Read method info...");
  184.  
  185.  
  186.         /*
  187.          * Identify all of the attributes in this class
  188.          */
  189.         count = di.readShort();
  190.         if (count != 0) {
  191.             attributes = new AttributeInfo[count];
  192.             for (int i = 0; i < count; i++) {
  193.                 attributes[i] = new AttributeInfo();
  194.                 if (! attributes[i].read(di, constantPool)) {
  195.                     return (false);
  196.                 }
  197.             }
  198.         }
  199.         if (debug) {
  200.             System.out.println("read(): Read attribute info...");
  201.             System.out.println("done.");
  202.         }
  203.         isValidClass = true;
  204.         return(true);
  205.     }
  206.  
  207.     /**
  208.      * Write the class out as a stream of bytes to the output
  209.      * stream.
  210.      *
  211.      * Generally you will read a class file, manipulate
  212.      * it in some way, and then write it out again before passing
  213.      * it to <TT>defineClass</TT> in some class loader.
  214.      */
  215.     public void write(OutputStream out)
  216.     throws IOException, Exception {
  217.         DataOutputStream dos = new DataOutputStream(out);
  218.  
  219.         if (! isValidClass) {
  220.             throw new Exception("ClassFile::write() - Invalid Class");
  221.         }
  222.  
  223.         dos.writeInt(magic);
  224.         dos.writeShort(majorVersion);
  225.         dos.writeShort(minorVersion);
  226.         dos.writeShort(constantPool.length);
  227.         for (int i = 1; i < constantPool.length; i++) {
  228.             if (constantPool[i] != null)
  229.                 constantPool[i].write(dos, constantPool);
  230.         }
  231.         dos.writeShort(accessFlags);
  232.         dos.writeShort(ConstantPoolInfo.indexOf(thisClass, constantPool));
  233.         dos.writeShort(ConstantPoolInfo.indexOf(superClass, constantPool));
  234.  
  235.         if (interfaces == null) {
  236.             dos.writeShort(0);
  237.         } else {
  238.             dos.writeShort(interfaces.length);
  239.             for (int i = 0; i < interfaces.length; i++) {
  240.                 dos.writeShort(ConstantPoolInfo.indexOf(interfaces[i],
  241.                             constantPool));
  242.             }
  243.         }
  244.  
  245.         if (fields == null) {
  246.             dos.writeShort(0);
  247.         } else {
  248.             dos.writeShort(fields.length);
  249.             for (int i = 0; i < fields.length; i++) {
  250.                 fields[i].write(dos, constantPool);
  251.             }
  252.         }
  253.  
  254.         if (methods == null) {
  255.             dos.writeShort(0);
  256.         } else {
  257.             dos.writeShort(methods.length);
  258.             for (int i = 0; i < methods.length; i++) {
  259.                 methods[i].write(dos, constantPool);
  260.             }
  261.         }
  262.  
  263.         if (attributes == null) {
  264.             dos.writeShort(0);
  265.         } else {
  266.             dos.writeShort(attributes.length);
  267.             for (int i = 0; i < attributes.length; i++) {
  268.                 attributes[i].write(dos, constantPool);
  269.             }
  270.         }
  271.     }
  272.  
  273.     /**
  274.      * Returns a string that represents what the access flags
  275.      * are set for. So 0x14 returns "public final "
  276.      */
  277.     public static String accessString(short flags) {
  278.         StringBuffer x = new StringBuffer();
  279.  
  280.         if ((flags & ACC_PUBLIC) != 0) {
  281.             x.append("public ");
  282.         }
  283.  
  284.         if ((flags & ACC_PRIVATE) != 0) {
  285.             x.append("private ");
  286.         }
  287.  
  288.         if ((flags & ACC_PROTECTED) != 0) {
  289.             x.append("protected ");
  290.         }
  291.  
  292.         if ((flags & ACC_STATIC) != 0) {
  293.             x.append("static ");
  294.         }
  295.  
  296.         if ((flags & ACC_FINAL) != 0) {
  297.             x.append("final ");
  298.         }
  299.  
  300.         if ((flags & ACC_SYNCHRONIZED) != 0) {
  301.             x.append("synchronized ");
  302.         }
  303.  
  304.         if ((flags & ACC_THREADSAFE) != 0) {
  305.             x.append("threadsafe ");
  306.         }
  307.  
  308.         if ((flags & ACC_TRANSIENT) != 0) {
  309.             x.append("transient ");
  310.         }
  311.  
  312.         if ((flags & ACC_NATIVE) != 0) {
  313.             x.append("native ");
  314.         }
  315.  
  316.         if ((flags & ACC_INTERFACE) != 0) {
  317.             x.append("interface ");
  318.         }
  319.  
  320.         if ((flags & ACC_ABSTRACT) != 0) {
  321.             x.append("abstract ");
  322.         }
  323.  
  324.         return (x.toString());
  325.     }
  326.  
  327.     /**
  328.      * Takes a type signature and a string representing a variable name
  329.      * and returns a declaration for that variable name.
  330.      *
  331.      * For example, passing this the strings "[B" and "myArray" will
  332.      * return the string "byte myArray[]"
  333.      */
  334.     public static String typeString(String typeString, String varName) {
  335.         int isArray = 0;
  336.         int    ndx = 0;
  337.         StringBuffer x = new StringBuffer();
  338.  
  339.         while (typeString.charAt(ndx) == '[') {
  340.             isArray++;
  341.             ndx++;
  342.         }
  343.  
  344.         switch (typeString.charAt(ndx)) {
  345.             case 'B' :
  346.                 x.append("byte ");
  347.                 break;
  348.             case 'C' :
  349.                 x.append("char ");
  350.                 break;
  351.             case 'D' :
  352.                 x.append("double ");
  353.                 break;
  354.             case 'F' :
  355.                 x.append("float ");
  356.                 break;
  357.             case 'I' :
  358.                 x.append("int ");
  359.                 break;
  360.             case 'J' :
  361.                 x.append("long ");
  362.                 break;
  363.             case 'L' :
  364.                 for (int i = ndx+1; i < typeString.indexOf(';'); i++) {
  365.                     if (typeString.charAt(i) != '/')
  366.                         x.append(typeString.charAt(i));
  367.                     else
  368.                     x.append('.');
  369.                 }
  370.                 x.append(" ");
  371.                 break;
  372.             case 'V':
  373.                 x.append("void ");
  374.                 break;
  375.             case 'S' :
  376.                 x.append("short ");
  377.                 break;
  378.             case 'Z' :
  379.                 x.append("boolean ");
  380.                 break;
  381.         }
  382.         x.append(varName);
  383.         while (isArray > 0) {
  384.             x.append("[]");
  385.             isArray--;
  386.         }
  387.         return (x.toString());
  388.     }
  389.  
  390.     /**
  391.      * Returns the next signature from a string of concatenated signatures.
  392.      * For example if the signature was "[BII", this method would return
  393.      * "II"
  394.      */
  395.     public static String nextSig(String sig) {
  396.         int    ndx = 0;
  397.         String     x;
  398.  
  399.         while (sig.charAt(ndx) == '[')
  400.             ndx++;
  401.  
  402.         if (sig.charAt(ndx) == 'L') {
  403.             while (sig.charAt(ndx) != ';')
  404.                 ndx++;
  405.         }
  406.         ndx++;
  407.         x =  (sig.substring(ndx));
  408.         return (x);
  409.     }
  410.  
  411.     /**
  412.      * Print the name of a class in "canonical form"
  413.      */
  414.     private String printClassName(String s) {
  415.         StringBuffer x;
  416.  
  417.         if (s.charAt(0) == '[') {
  418.             return(typeString(s, ""));
  419.         }
  420.  
  421.         x = new StringBuffer();
  422.         for (int j = 0; j < s.length(); j++) {
  423.             if (s.charAt(j) == '/')
  424.                 x.append('.');
  425.             else
  426.                 x.append(s.charAt(j));
  427.         }
  428.         return (x.toString());
  429.  
  430.     }
  431.  
  432.     public String getClassName() {
  433.         return printClassName(thisClass.arg1.strValue);
  434.     }
  435.  
  436.     /**
  437.      * The boring version of display().
  438.      */
  439.     public String toString() {
  440.         return("Class File (Version "+majorVersion+"."+minorVersion+
  441.             ") for class "+thisClass.arg1);
  442.     }
  443.  
  444.     /**
  445.      * Write out a text version of this class.
  446.      */
  447.     public void display(PrintStream ps)
  448.     throws Exception {
  449.         int i;
  450.         String myClassName;
  451.         String mySuperClassName;
  452.         String packageName = null;
  453.  
  454.         if (! isValidClass) {
  455.             ps.println("Not a valid class");
  456.         }
  457.  
  458.         myClassName = printClassName(thisClass.arg1.strValue);
  459.         mySuperClassName = printClassName(superClass.arg1.strValue);
  460.         if (myClassName.indexOf('.') > 0) {
  461.             packageName =
  462.                 myClassName.substring(0, myClassName.lastIndexOf('.'));
  463.             myClassName = myClassName.substring(myClassName.lastIndexOf('.')+1);
  464.             ps.println("package "+packageName+"\n");
  465.         }
  466.  
  467.         for (i = 1; i < constantPool.length; i++) {
  468.             if (constantPool[i] == null)
  469.                 continue;
  470.             if ((constantPool[i] == thisClass) ||
  471.                 (constantPool[i] == superClass))
  472.                 continue;
  473.             if (constantPool[i].type == ConstantPoolInfo.CLASS) {
  474.                 String s = constantPool[i].arg1.strValue;
  475.                     if (s.charAt(0) == '[')
  476.                         continue;
  477.                 s = printClassName(constantPool[i].arg1.strValue);
  478.                 if ((packageName != null) && (s.startsWith(packageName)))
  479.                     continue;
  480.                 ps.println("import "+printClassName(s)+";");
  481.             }
  482.         }
  483.         ps.println();
  484.         ps.println("/*");
  485.         DataInputStream dis;
  486.         ConstantPoolInfo cpi;
  487.  
  488.         if (attributes != null) {
  489.             ps.println(" * This class has "+attributes.length+
  490.                     " optional class attributes.");
  491.             ps.println(" * These attributes are: ");
  492.             for (i = 0; i < attributes.length; i++) {
  493.                 String attrName = attributes[i].name.strValue;
  494.                 dis = new DataInputStream(new ByteArrayInputStream(attributes[i].data));
  495.  
  496.                 ps.println(" * Attribute "+(i+1)+" is of type "+attributes[i].name);
  497.                 if (attrName.compareTo("SourceFile") == 0) {
  498.                     cpi = null;
  499.                     try {
  500.                         cpi = constantPool[dis.readShort()];
  501.                     } catch (IOException e) { }
  502.                     ps.println(" *    SourceFile : "+cpi);
  503.                 } else {
  504.                     ps.println(" *    TYPE ("+attrName+")");
  505.                 }
  506.             }
  507.         } else {
  508.             ps.println(" * This class has NO optional class attributes.");
  509.         }
  510.         ps.println(" */\n");
  511.         ps.print(accessString(accessFlags)+"class "+myClassName+" extends "+
  512.             mySuperClassName);
  513.         if (interfaces != null) {
  514.             ps.print(" implements ");
  515.             for (i = 0; i < interfaces.length - 1; i++) {
  516.                 ps.print(interfaces[i].arg1.strValue+", ");
  517.             }
  518.             ps.print(interfaces[interfaces.length-1].arg1.strValue);
  519.         }
  520.         ps.println(" {\n");
  521.         if (fields != null) {
  522.             ps.println("/* Instance Variables */");
  523.             for (i = 0; i < fields.length; i++) {
  524.                 ps.println("    "+fields[i].toString(constantPool)+";");
  525.             }
  526.         }
  527.  
  528.         if (methods != null) {
  529.             ps.println("\n/* Methods */");
  530.             for (i = 0; i < methods.length; i++) {
  531.                 ps.println("    "+methods[i].toString(myClassName));
  532.             }
  533.         }
  534.         ps.println("\n}");
  535.     }
  536.  
  537.     public ConstantPoolInfo getConstantRef(short index) {
  538.         return (constantPool[index]);
  539.     }
  540.  
  541.     /**
  542.      * Add a single constant pool item and return its index.
  543.      * If the item is already in the pool then the index of
  544.      * the <i>preexisting</i> item is returned. Thus you cannot
  545.      * assume that a pointer to your item will be useful.
  546.      */
  547.     public short addConstantPoolItem(ConstantPoolInfo item)
  548.     throws Exception {
  549.         ConstantPoolInfo newConstantPool[];
  550.         ConstantPoolInfo cp;
  551.  
  552.         cp = item.inPool(constantPool);
  553.         if (cp != null)
  554.             return ConstantPoolInfo.indexOf(cp, constantPool);
  555.  
  556.         newConstantPool = new ConstantPoolInfo[constantPool.length+1];
  557.         for (int i = 1; i < constantPool.length; i++) {
  558.             newConstantPool[i] = constantPool[i];
  559.         }
  560.         newConstantPool[constantPool.length] = item;
  561.         constantPool = newConstantPool;
  562.         return ConstantPoolInfo.indexOf(item, constantPool);
  563.     }
  564.  
  565.     /**
  566.      * Add some items to the constant pool. This is used to add new
  567.      * items to the constant pool. The items references in arg1 and
  568.      * arg2 are expected to be valid pointers (if necessary). Pruning
  569.      * is done to prevent adding redundant items to the list and to
  570.      * preserve string space.
  571.      *
  572.      * The algorithm is simple, first identify pool items containing
  573.      * constants in the list of items to be added that are already
  574.      * in the constant pool. If any are found to already exist, change
  575.      * the pointers in the non-constant items to point to the ones in
  576.      * the pool rather than the ones in the list. Next check to see
  577.      * if any of the non-constant items are already in the pool and
  578.      * if so fix up the others in the list to point to the ones in
  579.      * the pool. Finally, add any items (there must be at least one)
  580.      * from the item list that aren't already in the pool, all of
  581.      * the pointers will already be fixed.
  582.      *
  583.      * NOTE: Since constants in the constant pool may be referenced
  584.      * <i>inside</i> the opaque portion of attributes the constant
  585.      * table cannot be re-ordered, only extended.
  586.      */
  587.     public void addConstantPoolItems(ConstantPoolInfo items[]) {
  588.         ConstantPoolInfo newArg;
  589.         ConstantPoolInfo newConstantPool[];
  590.         boolean delete[] = new boolean[items.length];
  591.  
  592.         /* Step one, look for matching constants */
  593.         for (int j = 0; j < items.length; j++) {
  594.             if ( (items[j].type == ConstantPoolInfo.ASCIZ) ||
  595.                  (items[j].type == ConstantPoolInfo.UNICODE) ||
  596.                  (items[j].type == ConstantPoolInfo.INTEGER) ||
  597.                  (items[j].type == ConstantPoolInfo.LONG) ||
  598.                  (items[j].type == ConstantPoolInfo.FLOAT) ||
  599.                  (items[j].type == ConstantPoolInfo.DOUBLE)) {
  600.  
  601.             // Look for this item in the constant pool
  602.             delete[j] = false;
  603.             newArg = items[j].inPool(constantPool);
  604.             if (newArg != null) {
  605.                 // replace the references in our list.
  606.                 delete[j] = true;    // mark it for deletion
  607.                 for (int i = 0; i < items.length; i++) {
  608.                     if (items[i].arg1 == items[j])
  609.                         items[i].arg1 = newArg;
  610.                         if (items[i].arg2 == items[j])
  611.                             items[i].arg2 = newArg;
  612.                     }
  613.                 }
  614.             }
  615.         }
  616.  
  617.         /* Step two : now match everything else */
  618.         for (int j = 0; j < items.length; j++) {
  619.             if ( (items[j].type == ConstantPoolInfo.CLASS) ||
  620.                  (items[j].type == ConstantPoolInfo.FIELDREF) ||
  621.                  (items[j].type == ConstantPoolInfo.METHODREF) ||
  622.                  (items[j].type == ConstantPoolInfo.STRING) ||
  623.                  (items[j].type == ConstantPoolInfo.INTERFACE) ||
  624.                  (items[j].type == ConstantPoolInfo.NAMEANDTYPE)) {
  625.  
  626.             // Look for this item in the constant pool
  627.             delete[j] = false;
  628.             newArg = items[j].inPool(constantPool);
  629.             if (newArg != null) {
  630.                 // replace the references in our list.
  631.                 delete[j] = true;    // mark it for deletion
  632.                 for (int i = 0; i < items.length; i++) {
  633.                     if (items[i].arg1 == items[j])
  634.                         items[i].arg1 = newArg;
  635.                         if (items[i].arg2 == items[j])
  636.                             items[i].arg2 = newArg;
  637.                     }
  638.                 }
  639.             }
  640.         }
  641.  
  642.         /* Step three: Add the surviving items to the pool */
  643.         int count = 0;
  644.         for (int i = 0; i < items.length; i++) {
  645.             if (! delete[i])
  646.                 count++;
  647.         }
  648.         // count == # of survivors
  649.         newConstantPool = new ConstantPoolInfo[constantPool.length + count];
  650.         for (int i = 1; i < constantPool.length; i++) {
  651.             newConstantPool[i] = constantPool[i];
  652.         }
  653.         // newConstantPool == existing constantPool
  654.  
  655.         int ndx = 0;
  656.         for (int i = constantPool.length; i < newConstantPool.length; i++) {
  657.             while (delete[ndx])
  658.                 ndx++;
  659.             newConstantPool[i] = items[ndx];
  660.             ndx++;
  661.         }
  662.         // newConstantPool == existing + new
  663.         constantPool = newConstantPool;
  664.         // all done.
  665.     }
  666.  
  667.     /**
  668.      * Add a new optional class Attribute.
  669.      *
  670.      * Items is an array of constant pool items that are first added
  671.      * to the constant pool. At a minimum items[0] must be an ASCIZ
  672.      * item with the name of the attribute. If the body of the attribute
  673.      * references constant pool items these should be in the item list
  674.      * as well.
  675.      */
  676.     public void addAttribute(AttributeInfo newAttribute) {
  677.  
  678.         if (attributes == null) {
  679.             attributes = new AttributeInfo[1];
  680.             attributes[0] = newAttribute;
  681.         } else {
  682.             AttributeInfo newAttrList[] = new AttributeInfo[1+attributes.length];
  683.             for (int i = 0; i < attributes.length; i++) {
  684.                 newAttrList[i] = attributes[i];
  685.             }
  686.             newAttrList[attributes.length] = newAttribute;
  687.             attributes = newAttrList;
  688.         }
  689.     }
  690.  
  691.     /**
  692.      * Return the attribute named 'name' from the class file.
  693.      */
  694.     public AttributeInfo getAttribute(String name) {
  695.         if (attributes == null)
  696.             return null;
  697.         for (int i = 0; i < attributes.length; i++) {
  698.             if (name.compareTo(attributes[i].name.toString()) == 0)
  699.             return attributes[i];
  700.         }
  701.         return (null);
  702.     }
  703.  
  704.     /**
  705.      * Return a constant pool item from this class. (note does fixup
  706.      * of indexes to facilitate extracting nested or linked items.
  707.      */
  708.     public ConstantPoolInfo getConstantPoolItem(short index)
  709.     throws Exception {
  710.         ConstantPoolInfo cp;
  711.  
  712.         if ((index <= 0) || (index > (constantPool.length - 1)))
  713.             return (null);
  714.         cp = constantPool[index];
  715.         if (cp.arg1 != null)
  716.             cp.index1 = ConstantPoolInfo.indexOf(cp.arg1, constantPool);
  717.         if (cp.arg2 != null)
  718.             cp.index2 = ConstantPoolInfo.indexOf(cp.arg2, constantPool);
  719.         return cp;
  720.     }
  721.  
  722.     /* Examples of mysterious things you can do to a class file before
  723.      * writing it back out. These methods are not currently functional.
  724.      * (that would be too easy :-)
  725.      */
  726.  
  727.     /**
  728.      * Map occurences of class <i>oldClass</i> to occurrences of
  729.      * class <i>newClass</i>. This method is used to retarget
  730.      * accesses to one class, seamlessly to another.
  731.      *
  732.      * The format for the class name is slash (/) separated so
  733.      * the class <tt>util.ClassFile</tt> would be represented as
  734.      * <tt>util/ClassFile</tt>
  735.      */
  736.     public void mapClass(String oldClass, String newClass) {
  737.         if (debug)
  738.             System.out.println("Mapping class name "+oldClass+" ==> "+
  739.                 newClass+" for class "+thisClass.arg1);
  740.         for (int i = 0; i < constantPool.length; i++) {
  741.             if (constantPool[i].type == ConstantPoolInfo.CLASS) {
  742.                 String cname = constantPool[i].arg1.strValue;
  743.                 if (cname.compareTo(oldClass) == 0) {
  744.                     if (debug) {
  745.                         System.out.println("REPLACING "+cname+" with "+newClass);
  746.                     }
  747.                     constantPool[i].arg1.strValue = newClass;
  748.                 }
  749.             }
  750.         }
  751.     }
  752.  
  753.     /**
  754.      * Map occurences of package <i>oldPackage</i> to package
  755.      * <i>newPackage</i>.
  756.      *
  757.      * The format for the package name is slash (/) separated so
  758.      * the package <tt>java.util</tt> would be represented as
  759.      * <tt>java/util</tt>
  760.      */
  761.      public void mapPackage(String oldPackage, String newPackage) {
  762.         for (int i = 0; i < constantPool.length; i++) {
  763.             if (constantPool[i].type == ConstantPoolInfo.CLASS) {
  764.                 String cname = constantPool[i].arg1.strValue;
  765.                 if (cname.startsWith(oldPackage)) {
  766.                     constantPool[i].arg1.strValue = newPackage +
  767.                     cname.substring(cname.lastIndexOf('/'));
  768.                 }
  769.             }
  770.         }
  771.     }
  772.  
  773.     /**
  774.      * Delete a named method from this class. This method is used
  775.      * to excise specific methods from the loaded class. The actual
  776.      * method code remains, however the method signature is deleted
  777.      * from the constant pool. If this method is called by a class
  778.      * the exception IncompatibleClassChangeException is generated
  779.      * by the runtime.
  780.      */
  781.     public void deleteMethod(String name, String signature) {
  782.         for (int i = 0; i < constantPool.length; i++) {
  783.             if (constantPool[i].type == ConstantPoolInfo.CLASS) {
  784.             }
  785.         }
  786.     }
  787. }
  788.